'use strict';

/* global CloudCmd, DOM */
CloudCmd.EditNames = exports;

const currify = require('currify');
const exec = require('execon');
const supermenu = require('supermenu');
const multiRename = require('multi-rename');

const reject = Promise.reject.bind(Promise);

const Info = DOM.CurrentInfo;
const {Dialog} = DOM;

const refresh = currify(_refresh);
const rename = currify(_rename);

let Menu;

const ConfigView = {
    beforeClose: async () => {
        exec.ifExist(Menu, 'hide');
        DOM.Events.remove('keydown', keyListener);
        await isChanged();
    },
};

module.exports.init = async () => {
    await CloudCmd.Edit();
    
    setListeners();
};

module.exports.show = (options) => {
    const names = getActiveNames().join('\n');
    const config = {
        ...ConfigView,
        ...options,
    };
    
    if (Info.name === '..' && names.length === 1)
        return Dialog.alert.noFiles();
    
    DOM.Events.addKey(keyListener);
    
    CloudCmd.Edit
        .getEditor()
        .setValueFirst('edit-names', names)
        .setMode()
        .setOption('keyMap', 'default')
        .disableKey();
    
    CloudCmd.Edit.show(config);
    
    return CloudCmd.Edit;
};

async function keyListener(event) {
    const ctrl = event.ctrlKey;
    const meta = event.metaKey;
    const ctrlMeta = ctrl || meta;
    const {Key} = CloudCmd;
    
    if (ctrlMeta && event.keyCode === Key.S) {
        hide();
    } else if (ctrlMeta && event.keyCode === Key.P) {
        const [, pattern] = await Dialog.prompt('Apply pattern:', '[n][e]');
        pattern && applyPattern(pattern);
    }
}

function applyPattern(pattern) {
    const newNames = multiRename(pattern, getActiveNames());
    const editor = CloudCmd.Edit.getEditor();
    
    editor.setValue(newNames.join('\n'));
}

function getActiveNames() {
    return DOM.getFilenames(DOM.getActiveFiles());
}

module.exports.hide = hide;

function hide() {
    CloudCmd.Edit.hide();
}

function setListeners() {
    const element = CloudCmd.Edit.getElement();
    
    DOM.Events.addOnce('contextmenu', element, setMenu);
}

function applyNames() {
    const dir = Info.dirPath;
    const from = getActiveNames();
    const nameIndex = from.indexOf(Info.name);
    
    const editor = CloudCmd.Edit.getEditor();
    const to = editor
        .getValue()
        .split('\n');
    
    const root = CloudCmd.config('root');
    
    Promise
        .resolve(root)
        .then(rename(dir, from, to))
        .then(refresh(to, nameIndex))
        .catch(alert);
}

function _refresh(to, nameIndex, res) {
    if (res.status === 404)
        return res
            .text()
            .then(reject);
    
    const currentName = to[nameIndex];
    
    CloudCmd.refresh({
        currentName,
    });
}

function getDir(root, dir) {
    if (root === '/')
        return dir;
    
    return root + dir;
}

function _rename(path, from, to, root) {
    const dir = getDir(root, path);
    const {prefix} = CloudCmd;
    
    return fetch(`${prefix}/rename`, {
        method: 'put',
        credentials: 'include',
        body: JSON.stringify({
            from,
            to,
            dir,
        }),
    });
}

function setMenu(event) {
    const position = {
        x: event.clientX,
        y: event.clientY,
    };
    
    event.preventDefault();
    
    if (Menu)
        return;
    
    const editor = CloudCmd.Edit.getEditor();
    
    const options = {
        beforeShow: (params) => {
            params.x -= 18;
            params.y -= 27;
        },
        
        afterClick: () => {
            editor.focus();
        },
    };
    
    const menuData = {
        'Save           Ctrl+S': () => {
            applyNames();
            hide();
        },
        'Go To Line     Ctrl+G': () => {
            editor.goToLine();
        },
        'Cut            Ctrl+X': () => {
            editor.cutToClipboard();
        },
        'Copy           Ctrl+C': () => {
            editor.copyToClipboard();
        },
        'Paste          Ctrl+V': () => {
            editor.pasteFromClipboard();
        },
        'Delete         Del': () => {
            editor.remove('right');
        },
        'Select All     Ctrl+A': () => {
            editor.selectAll();
        },
        'Close          Esc': hide,
    };
    
    const element = CloudCmd.Edit.getElement();
    
    Menu = supermenu(element, options, menuData);
    
    Menu.addContextMenuListener();
    Menu.show(position.x, position.y);
}

module.exports.isChanged = isChanged;

async function isChanged() {
    const editor = CloudCmd.Edit.getEditor();
    const msg = 'Apply new names?';
    
    if (!editor.isChanged())
        return;
    
    const [, names] = await Dialog.confirm(msg);
    names && applyNames();
}
